<?php

/**
 * @Author: king
 * @Date:   2019-05-04 16:34:53
 * @Last Modified by:   king
 * @Last Modified time: 2019-06-07 15:50:56
 */
namespace App\Models\Api;
use App\Tools\Elasticsearch;
use App\Exceptions\ApiException;
use App\Models\Api\Base;
use AstroTool\Cache\CacheManage;
use Cache;


/**
 * 咨询师
 * Class LanmeiCounselor
 * @package App\Models\Api
 */
class LanmeiCounselor extends Base
{
    const COUNSELOR_ALL_IDS = 'counselor:all:ids';//所有咨询师id
    const COUNSELOR_HOT_IDS = 'counselor:hot:ids';//热门咨询师id
    const COUNSELOR_INFO = ':counselor:info:';//用户咨询师信息详情
    const CACHE_TIME = 86400 * 7;//缓存时间
    protected $table = 'counselor';

    /**
     * 保存或编辑咨询师信息
     * @param array $data
     * @param array $id
     * @return bool|false|int
     */
    public function saveCounselor($data = [], $id = [])
    {
        if (empty($id))
        {
            //新增
            try
            {
                $res =  $this->create($data);
            }
            catch (\Exception $e)
            {
               throw new ApiException('保存咨询师信息失败', 200, config('code.error'));
            }
        } else
        {
            //编辑
            try
            { 
                $res = $this->where(['id'=>"$id"])->update($data);
            }
            catch (\Exception $e)
            {
                throw new ApiException('保存咨询师信息失败', 200, config('code.error'));
            }
        }

        return $res;
    }

    /**
     * 获取咨询师列表id
     * @param array $map //筛选条件(type,price,level,grade,search)
     * @return array|bool
     * @throws \Exception
     */
    public function getCounselorLists($map = [])
    {
       // return $this->getCounselorListsFromElasticsearch($map);
        $where = [];
        $is_or = 0;
        $start_price = 0;
        $end_price = 999999;

        $start_level = 0;
        $end_level = 999999;

        //根据价格,等级进行筛选
        if ($map['type'] == 0 && $map['search'] == '')
        {
            $is_or = 1;
            switch (true)
            {
                case $map['price'] == 1:
                    $end_price = 100;
                    break;
                case $map['price'] == 2:
                    $start_price = 101;
                    $end_price = 300;
                    break;
                case $map['price'] == 3:
                    $start_price = 301;
                    $end_price = 500;
                    break;
                case $map['price'] == 4:
                    $start_price = 501;
                    break;
                case $map['level'] == 1:
                    $end_level = 1;
                    break;
                case $map['level'] == 2:
                    $start_level = 1;
                    $end_level = 2;
                    break;
                case $map['level'] == 3:
                    $start_level = 2;
                    $end_level = 3;
                    break;
                case $map['level'] == 4:
                    $start_level = 3;
                    break;
            }
        } else
        {
            //根据占星进行筛选
            if ($map['type'] == 1)
            {
                $type_name = 'stargazer_';
            } //根据占卜进行筛选
            else
            {
                $type_name = 'divination_';
            }

            switch (true)
            {
                case $map['price'] == 1:
                    $where[$type_name . 'price'] = ['between', [$start_price, 100]];
                    break;
                case $map['price'] == 2:
                    $where[$type_name . 'price'] = ['between', [101, 300]];
                    break;
                case $map['price'] == 3:
                    $where[$type_name . 'price'] = ['between', [301, 500]];
                    break;
                case $map['price'] == 4:
                    $where[$type_name . 'price'] = ['between', [501, $end_price]];
                    break;
                case $map['level'] == 1:
                    $where[$type_name . 'level'] = 1;
                    break;
                case $map['level'] == 2:
                    $where[$type_name . 'level'] = 2;
                    break;
                case $map['level'] == 3:
                    $where[$type_name . 'level'] = 3;
                    break;
                case $map['level'] == 4:
                    $where[$type_name . 'level'] = ['>', 3];
                    break;
            }

        }
        //根据评分进行筛选
        if ($map['grade'])
        {
            switch (true)
            {
                case $map['grade'] == 1:
                    $where['star_level'] = 5;
                    break;
                case $map['grade'] == 2:
                    $where['star_level'] = 4;
                    break;
                case $map['grade'] == 3:
                    $where['star_level'] = 3;
                    break;
                case $map['grade'] == 4:
                    $where['star_level'] = ['<', 3];
                    break;
            }
        }

        if ($map['filter_self'])
        {
            $where['uid'] = ['neq', $map['uid']];
        }

        if ($map['search'])
        {
            $where = ['nickname' => ['like', '%' . $map['search'] . '%']];
        }

        if ($is_or === 0)
        {
            try
            {
                $uids = $this->raw($where)->get(['id'])->toArray();

                // 将咨询师id组成字符串
                $uids = implode(',', $uids);

                // 缓存咨询师id,根据咨询师id
                if ($uids && $this->cache_on >= 1)
                {
                    Cache::set(self::COUNSELOR_ALL_IDS, $uids, self::CACHE_TIME);
                }

            }
            catch (\Exception $e)
            {
                $this->error = '获取咨询师列表失败';
                return false;
            }
        } else
        {
            $whereOr = "(divination_level between $start_level AND $end_level OR stargazer_level between $start_level AND $end_level) AND (divination_price between $start_price AND $end_price OR stargazer_price between $start_price AND $end_price)";
            try
            {
                $uids = $this
                    ->where($where)
                    ->whereRaw($whereOr)
                    ->get(['id'])->toArray();

                // 将咨询师id组成字符串
                $uids = implode(',', $uids);

                // 缓存咨询师id,根据咨询师id
                if ($uids && $this->cache_on >= 1)
                {
                    Cache::set(self::COUNSELOR_ALL_IDS, $uids, self::CACHE_TIME);
                }

            }
            catch (\Exception $e)
            {
                $this->error = '获取咨询师列表失败';
                return false;
            }
        }

        // 将咨询师id转为数组
        $all_course_ids = explode(',', $uids);

        $per_page = 10;// 当前文章评论每页显示数量

        // 统计有多少咨询师
        $total = count($all_course_ids);
        //获取数据分页信息
        $data_list = getPaginatorData($total, $map['page'], $per_page);

        //获取分页后的咨询师id数组
        $all_course_id = array_slice($all_course_ids, $data_list['start'], $per_page);

        unset($data_list['start']);
        unset($data_list['end']);

        $data = [];
        // 根据当前页课程id获取所需的课程信息
        if (!empty($all_course_id))
        {
            $ac_ids = [];
            $temp = [];

            // 从缓存课程内容,根据课程id
            foreach ($all_course_id as $ac_id)
            {
                if ($this->cache_on >= 1 && Cache::has($ac_id . self::COUNSELOR_INFO . $ac_id))
                {
                    // 根据课程id 获取课程内容
                    $temp[$ac_id] = Cache::get($ac_id . self::COUNSELOR_INFO . $ac_id);
                } else
                {
                    // 缓存未开启时，默认从数据库获取
                    $temp[$ac_id] = false;
                }
                // 课程内容未缓存，等待从数据库中获取
                if ($temp[$ac_id] === false && $ac_id)
                {
                    $ac_ids[] = $ac_id;
                }
            }

            if (!empty($ac_ids))
            {
                $data = $this->batchGetInfoByIds($ac_ids);
            }

            foreach ($temp as $item)
            {
                if ($item)
                {
                    $data[] = $item;
                }
            }
        }
        $data_list['data'] = $data;
        return $data_list;
    }

    /**
     * Elasticsearch 进行咨询师搜索
     * @param $map
     * @return array
     * @throws \Exception
     */
    public function getCounselorListsFromElasticsearch($map)
    {
        $query = [];

        if ($map['search'])
        {
            $query['bool']['must'][] = ['match' => ['nickname' => $map['search']]];
        }

        if ($map['filter_self'])
        {
            $query['bool']['must_not'][] = ['match' => ['uid' => $map['uid']]];
        }

        // 根据评分进行筛选
        if ($map['grade'])
        {
            switch ($map['grade'])
            {
                case 1:
                    $query['bool']['must'][] = ['match' => ['star_level' => 5]];
                    break;
                case 2:
                    $query['bool']['must'][] = ['match' => ['star_level' => 4]];
                    break;
                case 3:
                    $query['bool']['must'][] = ['match' => ['star_level' => 3]];
                    break;
                case 4:
                    $query['bool']['must'][] = ['range' => ['star_level' => ['lt' => 3]]];
                    break;
            }
        }
        // 搜索占星师
        if ($map['type'] === 1)
        {
            $query['bool']['must'][] = ['range' => ['stargazer_level' => ['gte' => 1]]];
        }// 搜索占卜师
        elseif ($map['type'] === 2)
        {
            $query['bool']['must'][] = ['range' => ['divination_level' => ['gte' => 1]]];
        }
        // 按价格搜索
        if ($map['price'])
        {
            switch ($map['price'])
            {
                case 1:
                    $priceCond = ['lte' => 100];
                    break;
                case 2:
                    $priceCond = ['gt' => 100, 'lte' => 300];
                    break;
                case 3:
                    $priceCond = ['gt' => 300, 'lte' => 500];
                    break;
                case 4:
                default:
                    $priceCond = ['gt' => 500];
                    break;
            }
            $query['bool']['must'][] = [
                'bool' => [
                    'should' => [
                        ['range' => ['stargazer_price' => $priceCond]],
                        ['range' => ['divination_price' => $priceCond]],
                    ]
                ]
            ];
        }
        // 按评分星级搜索
        if ($map['level'])
        {
            switch ($map['level'])
            {
                case 1:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['lte' => 5]]],
                                ['range' => ['divination_level' => ['lte' => 5]]],
                            ]
                        ]
                    ];
                    break;
                case 2:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['gt' => 5, 'lte' => 4]]],
                                ['range' => ['divination_level' => ['gt' => 5, 'lte' => 4]]],
                            ]
                        ]
                    ];
                    break;
                case 3:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['gt' => 4, 'lte' => 3]]],
                                ['range' => ['divination_level' => ['gt' => 4, 'lte' => 3]]],
                            ]
                        ]
                    ];
                    break;
                case 4:
                default:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['gt' => 3]]],
                                ['range' => ['divination_level' => ['gt' => 3]]],
                            ]
                        ]
                    ];
                    break;
            }
        }

        $data = Elasticsearch::getInstance()
            ->setParamFields('id')
            ->setParamIndex('counselor')
            ->setParamSize(10)
            ->setParamPage($map['page'])
//            ->setParamSort($sort)
            ->setParamWhere($query)
            ->search();

        $cids = array_column($data['data'], 'id');

        $data['data'] = $this->batchGetInfoByIds($cids);

        return $data;
    }

    /**
     * 获取热门所有咨询师的id
     * @return array|bool
     * @throws \Exception
     */
    public function getHotCounselor()
    {
        $page = 1;//分页起始页

        $hot_cids = false;

        if ($this->cache_on >= 1 && Cache::has(self::COUNSELOR_HOT_IDS))
        {
            $hot_cids = Cache::get(self::COUNSELOR_HOT_IDS);
        }

        // 获取所有咨询师id
        if ($hot_cids === false)
        {

            $where = ['counselor_status' => 1, 'is_hot' => 1];
            try
            {
                $hot_cids = $this
                    ->where($where)
                    ->orderBy('is_hot','DESC')
                    ->orderBy('accept','DESC')
                    ->pluck('id')->toArray();

                // 将咨询师id组成字符串
                if (!empty($hot_cids))
                {
                    $hot_cids = implode(',', $hot_cids);
                }

                // 缓存咨询师id,根据咨询师id
                if ($hot_cids && $this->cache_on >= 1)
                {
                    Cache::set(self::COUNSELOR_HOT_IDS, $hot_cids, self::CACHE_TIME);
                }

            }
            catch (\Exception $e)
            {
                throw new ApiException('获取上架的咨询师基本信息失败', 200, config('code.error'));
            }

        }
        // 将咨询师id转为数组
        $all_course_ids = explode(',', $hot_cids);

        $per_page = 10;// 当前热门咨询师每页显示数量

        // 统计有多少咨询师
        $total = count($all_course_ids);
        //获取数据分页信息
        $data_list = getPaginatorData($total, $page, $per_page);

        //获取分页后的咨询师id数组
        $all_course_id = array_slice($all_course_ids, $data_list['start'], $per_page);

        unset($data_list['start']);
        unset($data_list['end']);

        $data = [];
        // 根据当前页咨询师id获取所需的咨询师信息
        if (!empty($all_course_id))
        {
            $ac_ids = [];
            $temp = [];

            // 从缓存咨询师内容,根据咨询师id
            foreach ($all_course_id as $ac_id)
            {
                if ($this->cache_on >= 1 && Cache::has($ac_id . self::COUNSELOR_INFO))
                {
                    // 根据咨询师id 获取咨询师内容
                    $temp[$ac_id] = Cache::get($ac_id . self::COUNSELOR_INFO);
                } else
                {
                    // 缓存未开启时，默认从数据库获取
                    $temp[$ac_id] = false;
                }
                // 咨询师内容未缓存，等待从数据库中获取
                if ($temp[$ac_id] === false && $ac_id)
                {
                    $ac_ids [] = $ac_id;
                }
            }

            if (!empty($ac_ids))
            {
                $data = $this->batchGetInfoByIds($ac_ids);
            }

            foreach ($temp as $item)
            {
                if ($item)
                {
                    $data[] = $item;
                }
            }
        }
        return $data;
    }

    /**
     * 获取某个咨询师信息
     * @param array $map
     * @return array|bool
     */
    public function getCounselorInfo($map = [])
    {
        if (isset($map['cid']))
        {
            $where = ['c.id' => $map['cid']];
            $id = $map['cid'];
        } else
        {
            $where = ['c.uid' => $map['uid']];
            $id = $map['uid'];
        }
        $field = ['c.id','c.is_hot','c.uid','c.divination_level','c.stargazer_level','c.divination_integral','c.stargazer_integral','c.state','c.star_level','c.divination_price','c.stargazer_price','c.counselor_num','c.accept','c.grab_num','c.read_num','c.answer_num','c.nickname','c.intro','u.avatar','u.sex'];
        try
        {

            $data = $this
                ->from('counselor as c')
                ->select($field)
                ->join('user as u', 'c.uid','=','u.id', 'INNER')
                ->where($where)
                ->orderBy('id', 'DESC')
                ->first();
            $data = json_decode(json_encode($data, true), true);
            // 将咨询师内容缓存
            if ($this->cache_on >= 1)
            {
                Cache::set($id . self::COUNSELOR_INFO, $data, self::CACHE_TIME);
            }
        }
        catch (\Exception $e)
        {
           throw new ApiException('获取咨询师信息失败', 200, config('code.error'));
        }
        return $data;
    }

    /**
     * 通过IDS 在数据库中查找用户信息
     * @param array $ids
     * @return array
     * @throws ApiException
     */
    protected function getInfoByIdsInData(array $ids = [])
    {
        try
        {
            $data = $this->from('counselor as c')
                ->whereIn('c.id', $ids)
                ->join('user as u', 'c.uid','=','u.id')
                ->get(['c.id','c.create_time','c.update_time','c.counselor_status','c.is_hot','c.uid','c.divination_level','c.stargazer_level','c.divination_integral','c.stargazer_integral','c.state','c.star_level','c.divination_price','c.stargazer_price','c.counselor_num','c.accept','c.grab_num','c.read_num','c.answer_num','c.nickname','c.intro','u.avatar','u.sex'])->keyBy('id')->toArray();
        }
        catch (\Exception $e)
        {
            throw new ApiException('服务异常', 200, config('code.error'));
        }

        return $data;
    }

    /**
     * 批量通过咨询师ID获取咨询师信息
     * @param $cids
     * @param array $field
     * @return array
     * @throws \Exception
     */
    public function batchGetInfoByIds($cids, $field = [])
    {
        $cids = is_array($cids) ? $cids : explode(',', $cids);
        $data = CacheManage::getInstance()->setCacheConfig('counselor_info')
            ->batchGetCache($cids, function ($ids)
            {
                return $this->getInfoByIdsInData($ids);
            }, $field, 'list_details');

        return $data;
    }

    /**
     * 通过ID 获取咨询师信息
     * @param $cid
     * @param array $field
     * @return mixed
     * @throws \Exception
     */
    public function getInfoById($cid, $field = [])
    {
        $data = $this->batchGetInfoByIds($cid, $field);

        return current($data);
    }

    /**
     * 获取咨询师价格
     * @param $cids
     * @param int $problemType 占星/占卜
     * @return array
     * @throws \Exception
     */
    public function getCounselorsPrice($cids, $problemType)
    {
        $problemTypeName = $problemType == 1 ? '占星' : '占卜';

        if ($problemType == 1)
        {
            // 占星
            $field = ['id','stargazer_level','stargazer_price','state','counselor_status','nickname'];
            $counselorLevel = 'stargazer_level';
            $counselorPrice = 'stargazer_price';
        } else
        {
            // 占卜
            $field = ['id','divination_level','divination_price','state','counselor_status','nickname'];
            $counselorLevel = 'divination_level';
            $counselorPrice = 'divination_price';
        }
        // 查下咨询师数据
        $data = $this->batchGetInfoByIds($cids, $field);
       
        // 咨询师参数校验
        if (count(explode(',', $cids)) != ($people = count($data)))
        {
            throw new ApiException($problemTypeName . '师参数异常');
        }

        $priceData = [
            'totalPrice' => 0,
            'people' => $people,
            'counselorPrices' => []
        ];
        foreach ($data as $dataItem)
        {
            // 接单状态验证
            if ($dataItem['state'] === 0)
            {
                throw new ApiException($problemTypeName . '师 ' . $dataItem['nickname'] . ' 休息了！...');
            }
            // 咨询师判断
            if ($dataItem['counselor_status'] != 1 || $dataItem[$counselorLevel] == 0)
            {
                throw new ApiException($dataItem['nickname'] . ' ' . $problemTypeName . '师状态异常...');
            }
            // 统计总价
            $priceData['totalPrice'] += $dataItem[$counselorPrice];
            // 组合扩展对象
            $priceData['counselorPrices'][] = [
                'id' => $dataItem['id'],
                'level' => $dataItem[$counselorLevel],
                'price' => $dataItem[$counselorPrice],
                'nickname' => $dataItem['nickname']
            ];
        }
        // 返回价格信息
        return $priceData;
    }
        /**
     * 咨询师
     * @param $counselorGrade
     * @param $counselorMode
     * @return array up_level=>咨询师升级信息
     * @throws \Exception
     */
    public function sucIntegrUpdate($counselorGrade, $counselorMode)
    {
        $cids = array_keys($counselorGrade);

        $counselorModel = new LanmeiCounselor();

        $cName = $counselorMode == 1 ? 'stargazer' : 'divination';
        // 获取咨询师信息
        $cInfos = $counselorModel->batchGetInfoByIds($cids, [$cName . '_level', $cName . '_integral', 'uid']);
        // 咨询师等级信息
        $counselorLevel = LanmeiCounselorLevel::getCounselorLevel($counselorMode);

        $result = [];
        $integralRecord = [];
        foreach ($cInfos as $cid => $counselorInfo)
        {
            $update = [
                $cName . '_integral' => $this->raw($cName . '_integral+' . $counselorGrade[$cid]['integral']),// 积分增加
                'answer_num' => $this->raw('answer_num+1'), // 回答次数增加
            ];

            $nextLevel = $counselorInfo[$cName . '_level'] + 1; // 下一个等级
            if (($counselorGrade[$cid]['integral'] + $counselorInfo[$cName . '_integral']) >= $counselorLevel[$nextLevel]['integral']) //判断等级是否提升
            {
                $update[$cName . '_level'] = $nextLevel;
                $update[$cName . '_price'] = $counselorLevel[$nextLevel]['price'];

                $result['up_level'][$cid] = [
                    'level' => $counselorLevel[$nextLevel]['level'],
                    'type' => $counselorMode,
                    'level_name' => $counselorLevel[$nextLevel]['name'],
                    'uid' => $counselorInfo['uid']
                ];
            }
            // 组合积分历史记录
            $integralRecord[] = [
                'c_id' => $cid,
                'ca_id' => $counselorGrade[$cid]['ca_id'],
                'integral' => $counselorGrade[$cid]['integral'],
                'create_time' => $counselorGrade[$cid]['create_time'],
                'counselor_mode' => $counselorMode,
            ];

            $this->where('id', $cid)->update($update);
        }

        (new LanmeiCounselorIntegralRecord())->create($integralRecord); // 写入积分记录

        return $result;
    }

  /**
     * 咨询师 评分统计-->平均评分 采纳率-->更新
     * @param $data
     * @return bool
     * @throws Exception
     * @throws \Exception
     */
    public function integralStatistics($data)
    {
        $answerCommentModel = new LanmeiCounselorAnswerComment();

        $updateData = [];
        foreach ($data as $cid => $info)
        {
            $accept = $this->acceptStatistics($cid);
            // 统计 咨询师 评分
            $grade = $answerCommentModel->where('c_id', $cid)->avg('grade');
            // 格式化 评分
            $grade = round($grade, 1);
            // 组合更新咨询师数据
            $updateData[$cid] = [
                'star_level' => $grade,
                'accept' => $accept
            ];
            // 更新咨询师 用户点评 和缓存
            LanmeiCommentTag::updateCounselorComment($cid);
            // 更新咨询师星级
            $this->save($updateData[$cid], ['id' => $cid]);
        }
        // 更新咨询师信息缓存
        CacheManage::getInstance()->setCacheConfig('counselor_info')->batchSetCache($updateData, 'list_details', true);

        return true;
    }

    /**
     * 获取 咨询师 采纳率
     * @param $cid
     * @return float|int
     * @throws Exception
     * @throws \Exception
     */
    protected function acceptStatistics($cid)
    {   // 获取采纳总次数
        $acceptNum = (new LanmeiCounselorAnswer())->where('c_id', $cid)->where('is_accept', 1)->count();

        if ($acceptNum == 0)
        {
            return $acceptNum;
        }

        $info = $this->getInfoById($cid, ['answer_num']);

        $accept = ($acceptNum / $info['answer_num']) / 100;

        $accept = round($accept, 1);

        return $accept;
    }

}
